package backend.rss;

import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;

import backend.rss.items.AuthorItem;
import backend.rss.items.CommentItem;
import backend.rss.items.DetailedThemeItem;
import backend.rss.items.SwatchItem;
import backend.rss.items.TagItem;
import backend.rss.items.ThemeItem;


public class KulerRSSFeed
{
	private static final DateFormat DATEFORMAT = new SimpleDateFormat("yyyyMMdd");
	private static final DateFormat COMMENT_DATEFORMAT = new SimpleDateFormat("MM/dd/yyyy");
	private static final DateFormat DETAILED_DATEFORMAT = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
	public static final String URI = "http://kuler.adobe.com/kuler/API/rss/";
	
	public enum ParseType {THEME, COMMENT, DETAILED_THEME};
	
	private Document document;
	private Namespace kulerNamespace = Namespace.getNamespace("kuler", URI);
	private ItemsContainer itemsInFeed;
	
	public KulerRSSFeed(String url)
	{
		this(url, ParseType.THEME);
	}
	
	public KulerRSSFeed(String url, ParseType parseType )
	{
		SAXBuilder builder = new SAXBuilder();
		try
		{
			document = builder.build(url);
			itemsInFeed = new ItemsContainer();
			
			if (parseType == ParseType.THEME) parseTheme();
		}
		catch (JDOMException e)
		{
			e.printStackTrace();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	
	private void parseTheme()
	{
		parseItems(parseHeader());
	}
	
	private List<Element> parseHeader()
	{
		//the channel here is our root in question
		Element root = document.getRootElement().getChild("themeList");

		itemsInFeed.setRecordCount(Integer.parseInt(root.getChildText("recordCount")));
		itemsInFeed.setStartIndex(Integer.parseInt(root.getChildText("startIndex")));
		itemsInFeed.setItemsPerPage(Integer.parseInt(root.getChildText("itemsPerPage")));
		return root.getChildren("theme");
	}
	
	public DetailedThemeItem parseDetailedTheme()
	{
		Element root 					= document.getRootElement().getChild("theme");
		
		Map<String, Object> themeData 	= parseThemeData(root);
		AuthorItem author				= getAuthorItem(root.getChild("author"));
				
		Element swatches				= root.getChild("swatches");
		
		List<SwatchItem> themeSwatches 	= parseSwatches(swatches.getChildren());
		
		Element comments				= root.getChild("comments");
		List<CommentItem> themeComments = parseComments(comments.getChildren());
		
		Element tags					= root.getChild("tags");
		List<TagItem> tagItems 			= parseTags(tags.getChildren());
		

		DetailedThemeItem themeItem		= new DetailedThemeItem((String)themeData.get("id"), 
																(String)themeData.get("label"), 
																author, 
																(Integer)themeData.get("rating"),
																(Float)themeData.get("ratingFractional"), 
																(Integer)themeData.get("userRating"), 
																(Integer)themeData.get("votes"), 
																(Integer)themeData.get("downloads"), 
																(Integer)themeData.get("numFavorites"), 
																(Date)themeData.get("createdAt"), 
																(Date)themeData.get("editedAt"), 
																themeSwatches, 
																themeComments, 
																tagItems);
		return themeItem;
	}
	
	
	private List<SwatchItem> parseSwatches(List<Element> items)
	{
		List<SwatchItem> swatches = new ArrayList<SwatchItem>(items.size());
		
		for (Element swatch : items)
		{
			String swatchHexColor 	= swatch.getChildText("hexColor");
			String swatchColorMode 	= swatch.getChildText("mode");
			float swatchChannel1 	= Float.parseFloat(swatch.getChildText("c1"));
			float swatchChannel2 	= Float.parseFloat(swatch.getChildText("c2"));
			float swatchChannel3 	= Float.parseFloat(swatch.getChildText("c3"));
			float swatchChannel4 	= Float.parseFloat(swatch.getChildText("c4"));
			String swatchIndex 		= swatch.getChildText("index");

			swatches.add(new SwatchItem(swatchIndex, 
								 		swatchColorMode,
								 		swatchHexColor, 
								 		swatchChannel1, 
								 		swatchChannel2, 
								 		swatchChannel3,
								 		swatchChannel4));			
		}
		return swatches;
	}
	
	private List<CommentItem> parseComments(List<Element> items)
	{
		List<CommentItem> comments = new ArrayList<CommentItem>(items.size());
		
		if (items != null)
		{
			for (Element item : items)
			{
				String id = item.getChildText("id");
				int index = parseChildTextToInt(item.getChildText("index"));
				Date posted = formatDateRFC822(item.getChildText("postedAt"));
				String text = item.getChildText("label");

				AuthorItem author = getAuthorItem(item.getChild("author"));

				CommentItem comment = new CommentItem(id, text, posted, author);
				comments.add(comment);
			}
		}
		return comments;
	}
	
	private List<TagItem> parseTags(List<Element> items)
	{
		List<TagItem> tags = new ArrayList<TagItem>(items.size());
		
		if (items != null)
		{
			for (Element item : items)
			{
				String id	= item.getChildText("id");
				String label= item.getChildText("label");
				int weight 	= parseChildTextToInt(item.getChildText("weight"));
				
				TagItem tag = new TagItem(id, label, weight);
				
				tags.add(tag);
			}
		}
		return tags;
	}
	
	private AuthorItem getAuthorItem(Element item)
	{
		String id 	= item.getChildText("id");
		String name = item.getChildText("label");
		String image= item.getChildText("image");
		
		//locate in map, and return that if it's there, else create a new author object
		AuthorItem author = itemsInFeed.getAuthor(id);
		if (author != null) return author;
		else return new AuthorItem(id, name, image);
	}
	
	private Date formatDateRFC822(String date)
	{
		if (date == null || date.equals("")) return null;
		
		//Adobe's server is GMT-8, but the time output in the xml doesn't have timezone, so lets append one
		date += "-0800";

		try
		{
			Date d = DETAILED_DATEFORMAT.parse(date);
			return d;
		}
		catch (ParseException e)
		{
			e.printStackTrace();
			return null;
		}
	}
	
	private int parseChildTextToInt(String toParse)
	{
		if (toParse == null || toParse.equals("")) return 0;
		else return Integer.parseInt(toParse);
	}
	
	private float parseChildTextToFloat(String toParse)
	{
		if (toParse == null || toParse.equals("")) return 0;
		else return Float.parseFloat(toParse);		
	}
	
	private Map<String, Object> parseThemeData(Element root)
	{
		String themeId		= root.getChildText("id");
		String themeTitle	= root.getChildText("label", root.getNamespace());
		
		int rating			= parseChildTextToInt(root.getChildText("rating"));
		float ratingFract	= parseChildTextToFloat(root.getChildText("ratingFractional"));
		int userRating		= parseChildTextToInt(root.getChildText("userRating"));
		int votes			= parseChildTextToInt(root.getChildText("votes"));
		int downloads		= parseChildTextToInt(root.getChildText("downloads"));
		int numFavourites	= parseChildTextToInt(root.getChildText("numFavorites"));
		Date dateCreated	= formatDateRFC822(root.getChildText("createdAt"));
		Date dateEdited		= formatDateRFC822(root.getChildText("editedAt"));
		
		Map<String, Object> result = new HashMap<String, Object>();
		result.put("id", themeId);
		result.put("label", themeTitle);
		result.put("rating", rating);
		result.put("ratingFractional", ratingFract);
		result.put("userRating", userRating);
		result.put("votes", votes);
		result.put("downloads", downloads);
		result.put("numFavorites", numFavourites);
		result.put("createdAt", dateCreated);
		result.put("editedAt", dateEdited);
		
		return result;
	}

	private void parseItems(List<Element> items)
	{
		for (Element root : items)
		{			
			Map<String, Object> themeData 		= parseThemeData(root);
			AuthorItem author					= getAuthorItem(root.getChild("author"));

			List<SwatchItem> swatches 			= parseSwatches(root.getChild("swatches").getChildren());

			ThemeItem themeItem = new ThemeItem((String)themeData.get("id"), 
												(String)themeData.get("label"), 
												author, 
												(Integer)themeData.get("rating"),
												(Float)themeData.get("ratingFractional"),
												(Integer)themeData.get("userRating"),
												(Date)themeData.get("createdAt"),
												(Date)themeData.get("editedAt"),
												swatches);

			author.addThemeItem(themeItem);
			itemsInFeed.addItem(themeItem);
			itemsInFeed.addItem(author);
			
		}
	}

	/**
	 * @return the itemsInFeed
	 */
	public ItemsContainer getItemsInFeed()
	{
		return itemsInFeed;
	}


}
